123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738 |
- import { GameListRep } from "@/api/home";
- import { userInfoApi } from "@/api/login";
- import { ChannelType, WithDrawParams, WithDrawType, getWithDrawApi } from "@/api/withdraw";
- import { clearWallet } from "@/app/[locale]/(navbar)/withdraw/actions";
- import TipsModal, { ModalProps } from "@/components/TipsModal";
- import { ChannelEnum, ChannelEnumMap } from "@/enums";
- import useGame from "@/hooks/useGame";
- import { useRouter } from "@/i18n/routing";
- import { useSystemStore } from "@/stores/useSystemStore";
- import { useUserInfoStore } from "@/stores/useUserInfoStore";
- import { useWalletStore } from "@/stores/useWalletStore";
- import { isEmail } from "@/utils";
- import { server } from "@/utils/client";
- import { percentage } from "@/utils/methods";
- import { Button, Form, Input, ProgressBar, Toast } from "antd-mobile";
- import BigNumber from "bignumber.js";
- import clsx from "clsx";
- import { useTranslations } from "next-intl";
- import React from "react";
- import { Swiper, SwiperSlide } from "swiper/react";
- import styles from "./index.module.scss";
- const getWithdrawApi = async () => {
- return server
- .request<WithDrawType[]>({
- url: "/v1/api/user/user_withdraw_config",
- method: "post",
- })
- .then((res) => {
- if (res.code === 200) {
- return res.data;
- }
- return [];
- });
- };
- const Withdraw = () => {
- const t = useTranslations();
- const router = useRouter();
- const { getGameUrl } = useGame();
- const [configData, setConfigData] = React.useState<WithDrawType[]>([] as WithDrawType[]);
- const [currentChannel, setCurrentChannel] = React.useState<WithDrawType>({} as WithDrawType);
- const [currentType, setCurrentType] = React.useState<ChannelType>({} as ChannelType);
- const [amount, setAmount] = React.useState<string>("");
- const { wallet } = useWalletStore();
- const isStrictMode = useSystemStore((state) => state.identity_verify.withdraw === 1);
- const userInfo = useUserInfoStore((state) => state.userInfo);
- // const canWithdrawRef = React.useRef<ModalProps>(null);
- const formInstanceRef = React.useRef<any>(null);
- const scoreRef = React.useRef<ModalProps>(null);
- const gameModelRef = React.useRef<ModalProps>(null);
- const game = React.useRef<GameListRep | null>(null);
- const successModelRef = React.useRef<ModalProps | null>(null);
- React.useEffect(() => {
- getData();
- }, []);
- React.useEffect(() => {
- formInstanceRef.current?.resetFields(["account_no"]);
- }, [currentType]);
- React.useEffect(() => {
- formInstanceRef.current?.resetFields();
- setAmount("");
- }, [currentChannel]);
- const quicks = React.useMemo(() => {
- return [200, 500, 1000, 10000];
- }, []);
- const faltaData = React.useMemo(() => {
- const {
- target_score_rollover,
- current_score_rollover,
- score,
- point,
- target_point_rollover,
- current_point_rollover,
- } = wallet;
- const total = target_score_rollover + target_point_rollover;
- const current = current_score_rollover + current_point_rollover;
- const waitScore = target_score_rollover - current_score_rollover;
- const waitPoint = target_point_rollover - current_point_rollover;
- let canWithdraw = true;
- if (waitScore !== 0 || waitPoint !== 0) {
- canWithdraw = false;
- }
- return {
- canWithdraw,
- percent: percentage(current, total),
- percentScore: (current_score_rollover / target_score_rollover) * 100,
- percentPoint: (current_point_rollover / target_point_rollover) * 100,
- waitScore,
- waitPoint,
- wait: waitScore + waitPoint,
- point,
- score: score || 0,
- };
- }, [wallet]);
- const getData = async () => {
- const res = await getWithdrawApi();
- if (res?.length > 0) {
- setConfigData(res);
- if (res[0]) {
- const cChannel = res[0];
- setCurrentChannel(cChannel);
- const ctype = cChannel?.channels;
- if (ctype && ctype?.length > 0) {
- setCurrentType(ctype[0] || {});
- }
- }
- }
- };
- const channelChangeHandler = (item: WithDrawType) => {
- setCurrentChannel(item);
- if (item?.channels && item?.channels?.length > 0) {
- setCurrentType(item.channels[0]);
- }
- };
- const valuesChange = (data: any) => {
- for (let key in data) {
- let curValue = data[key].trim();
- switch (key) {
- case "amount":
- {
- let max = currentChannel.max_amount;
- if (faltaData.score < currentChannel.max_amount) {
- max = faltaData.score;
- }
- const toValue = inputNumber(curValue, { max });
- setAmount(toValue);
- formInstanceRef.current?.setFieldValue(key, toValue);
- }
- break;
- case "account_no":
- {
- if (currentType.type === ChannelEnum.CPF) {
- const toValue = inputNumber(curValue, { length: 11 });
- formInstanceRef.current?.setFieldValue(key, toValue);
- }
- if (currentType.type === ChannelEnum.CNPJ) {
- const toValue = inputNumber(curValue, { length: 14 });
- formInstanceRef.current?.setFieldValue(key, toValue);
- }
- if (currentType.type === ChannelEnum.Phone) {
- const toValue = inputNumber(curValue, { length: 11 });
- formInstanceRef.current?.setFieldValue(key, toValue);
- }
- if (currentType.type === ChannelEnum.Email) {
- const toValue = curValue.replace(/\s/gi, "");
- formInstanceRef.current?.setFieldValue(key, toValue);
- }
- }
- break;
- case "passport":
- {
- const toValue = inputNumber(curValue, { length: 11 });
- formInstanceRef.current?.setFieldValue(key, toValue);
- }
- break;
- }
- }
- };
- const inputNumber = (
- value: string,
- opts?: {
- max?: number;
- length?: number;
- }
- ) => {
- const toValue = value.replace(/[^0-9]/, "");
- let toAmount = "";
- if (toValue) {
- toAmount = new BigNumber(toValue).toFixed(0, BigNumber.ROUND_DOWN);
- }
- if (opts?.max !== undefined && new BigNumber(toAmount).isGreaterThan(opts.max)) {
- toAmount = opts.max.toString();
- }
- if (opts?.length && toAmount.length > opts.length) {
- toAmount = toAmount.slice(0, opts.length);
- }
- return toAmount;
- };
- const ChannelValidator = (rules: any, value: string) => {
- if (!value) return Promise.reject(new Error(t("WithdrawPage.channel")));
- if (currentType.type === ChannelEnum.CPF) {
- return value.length !== 11
- ? Promise.reject(new Error(t("WithdrawPage.cpfReg")))
- : Promise.resolve();
- }
- if (currentType.type === ChannelEnum.CNPJ) {
- return value.length !== 14
- ? Promise.reject(new Error(t("WithdrawPage.cnpjReg")))
- : Promise.resolve();
- }
- if (currentType.type === ChannelEnum.Email) {
- return isEmail(value)
- ? Promise.resolve()
- : Promise.reject(new Error(t("WithdrawPage.EmailReg")));
- }
- if (currentType.type === ChannelEnum.Phone) {
- return value.length < 10
- ? Promise.reject(new Error(t("WithdrawPage.phoneReg")))
- : Promise.resolve();
- }
- return Promise.resolve();
- };
- const onFinish = async (value: any) => {
- const { data } = await userInfoApi();
- if (
- faltaData.score <= currentChannel.min_amount ||
- new BigNumber(value.amount).isGreaterThan(faltaData.score) ||
- faltaData.waitPoint !== 0 ||
- faltaData.waitScore !== 0
- ) {
- Toast.show("Quantidade insuficiente disponível para retirada");
- return;
- }
- // 如果有未完成游戏
- if (data.play_list && data.play_list.length > 0) {
- game.current = data.play_list[0];
- gameModelRef.current?.onOpen();
- return;
- }
- extractHandler();
- };
- const extractHandler = async () => {
- const values = formInstanceRef.current?.getFieldValues();
- const { passport, name, last_name, amount, account_no } = values;
- if (!amount) {
- return;
- }
- const params: WithDrawParams = {
- passport,
- channel_id: currentType.id,
- amount: Number(amount),
- account_no,
- user_name: `${name} ${last_name}`,
- };
- const withResult = await getWithDrawApi(params).catch((error) => {
- Toast.show(t(`code.${error.data.code}`));
- });
- if (withResult && withResult.code === 200) {
- Toast.show(t("code.200"));
- }
- await clearWallet();
- };
- // const goGame = () => {
- // const current = game.current;
- // getGameUrl(current!, { id: current?.id + "" });
- // };
- // const doCleanBonus = async () => {
- // try {
- // const res = await getUserTransferApi({ wallet_type: 2 });
- // if (res.code === 200) {
- // Toast.show(t("code.200"));
- // setTimeout(() => {
- // successModelRef.current?.onClose();
- // }, 1000);
- // }
- // } catch (error: any) {
- // Toast.show(t(`code.${error?.data?.code}`));
- // }
- // };
- return (
- <div className={styles.withdrawPage}>
- <div className={styles.swiperContainer}>
- <Swiper slidesPerView={3} spaceBetween={10} style={{ width: "100%" }}>
- {configData?.map((item, index) => (
- <SwiperSlide key={index}>
- <div
- className={clsx(
- styles.buttonItem,
- {
- [styles.active]: currentChannel?.id === item.id,
- },
- "iconfont"
- )}
- onClick={() => channelChangeHandler(item)}
- >
- <div className="text-center text-[.15rem]">
- {/* <img
- className="inline-block h-[.15rem]"
- src={item.icon}
- alt=""
- /> */}
- {item.name}
- </div>
- <div className="mt-[.02rem] text-[.13rem] text-[#11de68]">
- R${item.min_amount}~{item.max_amount}
- </div>
- </div>
- </SwiperSlide>
- ))}
- </Swiper>
- </div>
- <div className={styles.withdrawTitle}>
- <div className={styles.withdrawTitleText}>
- <span className="mr-[.1rem]">ContaSaldo</span>
- <span className="text-[#11de68]">
- R$ {faltaData.canWithdraw ? faltaData.score : 0}
- </span>
- </div>
- <i
- className="iconfont icon-22222_huaban1 text-[#eac61f]"
- onClick={() => {
- scoreRef.current?.onOpen();
- }}
- ></i>
- </div>
- {/* <div className="pb-[.1rem] text-[#74888f]">Valor do Saque</div> */}
- {/* <div className={styles.quick}>
- {quicks.map((item) => {
- return (
- <div
- className={clsx(
- styles.buttonItem,
- {
- [styles.active]: Number(amount) === item,
- },
- "iconfont flex h-[.44rem] flex-col items-center justify-center"
- )}
- key={item}
- onClick={() => {
- formInstanceRef.current?.setFieldValue("amount", item);
- setAmount(`${item}`);
- }}
- >
- <div className="text-[.16rem] text-[#11de68]">R$ {item}</div>
- </div>
- );
- })}
- </div> */}
- <div className="flex items-center py-[.1rem]">
- <i className="iconfont icon-22222_huaban1 mr-[.1rem] text-[#789098]"></i>
- <span className="text-[.12rem] text-[#eac61f]">
- A retirada minima após depositar R$ 10 é R$ 20
- </span>
- </div>
- <div>
- <Form ref={formInstanceRef} onFinish={onFinish} onValuesChange={valuesChange}>
- <Form.Item
- className={styles.amontForm}
- label={<div className="px-[.1rem]">R$</div>}
- layout="horizontal"
- extra={
- <div
- className={styles.todos}
- onClick={() => {
- let toValue = 0;
- if (faltaData.canWithdraw) {
- toValue = faltaData.score;
- }
- formInstanceRef.current?.setFieldValue("amount", `${toValue}`);
- setAmount(`${toValue}`);
- }}
- >
- Todos
- </div>
- }
- name="amount"
- >
- <Input
- className={styles.amountInput}
- onChange={(value) => setAmount(value)}
- placeholder={`${currentChannel.min_amount}~${currentChannel.max_amount}`}
- />
- </Form.Item>
- <div className={styles.line}></div>
- <div className={styles.channelText}>
- <span className="mr-[.1rem] text-[.14rem] text-[#768d95]">
- Método de Retirada
- </span>
- {currentChannel.icon && (
- <div className="rounded-[.04rem] border-[1px] border-[#16432f] px-[.06rem] py-[.02rem]">
- <img className="h-[.2rem]" src={currentChannel.icon} alt="" />
- </div>
- )}
- </div>
- <div>
- <Swiper slidesPerView={3} spaceBetween={10} style={{ width: "100%" }}>
- {currentChannel.channels?.map((item, index) => (
- <SwiperSlide key={index}>
- <div
- className={clsx(
- styles.buttonItem,
- {
- [styles.active]: currentType?.id === item.id,
- },
- "iconfont"
- )}
- onClick={() => setCurrentType(item)}
- >
- <div className="py-[.08rem] text-[.12rem]">
- {ChannelEnum[item.type]}
- </div>
- </div>
- </SwiperSlide>
- ))}
- </Swiper>
- </div>
- {(isStrictMode || currentType.type === ChannelEnum.CPF) && (
- <div className="mt-[.1rem] flex items-center">
- <Form.Item
- label="Nome"
- className="mr-[.1rem] w-[1.5rem] border-b-[1px] border-[#3b4852]"
- rules={[{ required: true }]}
- name="name"
- >
- <Input placeholder="Insira seu nome"></Input>
- </Form.Item>
- <Form.Item
- rules={[{ required: true }]}
- className="flex-1 border-b-[1px] border-[#3b4852]"
- label="Sobrenome"
- name="last_name"
- >
- <Input placeholder="Insira seu sobrenome"></Input>
- </Form.Item>
- </div>
- )}
- {isStrictMode && currentType.type !== ChannelEnum.CPF && (
- <Form.Item
- label={"CPF ID"}
- className="mt-[.1rem] border-b-[1px] border-[#3b4852]"
- name={"passport"}
- rules={[{ validator: ChannelValidator }]}
- >
- <Input
- className={clsx("flex-1")}
- placeholder={ChannelEnumMap.get(ChannelEnum.CPF)?.placeholder ?? ""}
- ></Input>
- </Form.Item>
- )}
- <Form.Item
- label={ChannelEnumMap.get(currentType.type)?.text}
- className="mt-[.1rem] border-b-[1px] border-[#3b4852]"
- name={"account_no"}
- rules={[{ validator: ChannelValidator }]}
- >
- <Input
- className={clsx("flex-1", {
- [styles.accountNo]: currentType.type === ChannelEnum.Phone,
- })}
- placeholder={ChannelEnumMap.get(currentType.type)?.placeholder ?? ""}
- ></Input>
- </Form.Item>
- </Form>
- <div className={styles.btns}>
- <Button
- className={styles.btn}
- onClick={() => formInstanceRef.current?.submit()}
- >
- Sacar
- </Button>
- <Button
- className={styles.btn}
- onClick={() => {
- router.push("/transactions?type=2");
- }}
- >
- Histórico
- </Button>
- </div>
- </div>
- {/* 可以提取弹窗 */}
- {/* <TipsModal
- title={
- <div className={"flex items-center text-[#11de68]"}>
- <i
- className={"iconfont icon-liwuhuodong mr-[0.0694rem] text-[0.2778rem]"}
- ></i>
- SACAR
- </div>
- }
- ref={canWithdrawRef}
- getContainer={document.querySelector("#app")}
- className={styles.ModalBox}
- >
- <ul>
- <li className={"mb-[0.0694rem]"}>
- <span className="mr-[.1rem]">{t("WithdrawPage.scoreTips")}</span>
- <span>
- <i className="mr-[.1rem]">R$</i>
- {wallet.score}
- </span>
- </li>
- <li>
- <div className={"flex items-center"}>
- <ProgressBar
- percent={faltaData.percentScore} //faltaData.percent
- className={"mr-[0.0694rem] flex-1"}
- style={{
- "--fill-color": "#11de68",
- "--track-color": "#8f9498",
- "--track-width": "0.0694rem",
- }}
- />
- <span>{faltaData.percentScore}%</span>
- </div>
- <div>
- <span className="mr-[.1rem]">FALTA APOSTAR</span>
- <span> R$ {faltaData.waitScore}</span>
- </div>
- </li>
- </ul>
- </TipsModal> */}
- {/*有彩金弹窗*/}
- <TipsModal
- title={
- <div className={"flex items-center text-[#11de68]"}>
- <i
- className={"iconfont icon-liwuhuodong mr-[0.0694rem] text-[0.2778rem]"}
- ></i>
- SACAR
- </div>
- }
- ref={scoreRef}
- getContainer={document.querySelector("#app")}
- className={styles.ModalBox}
- >
- <ul>
- <li className={"mb-[0.0694rem]"}>
- <span className="mr-[.1rem] inline-block w-[.6rem]">Conta Saldo</span>
- <span>
- <i className="mr-[.1rem] font-bold">R$</i>
- {faltaData.canWithdraw ? faltaData.score : 0}
- </span>
- </li>
- <li className={"mb-[0.0694rem]"}>
- <span className="mr-[.1rem] inline-block w-[.6rem]">
- {t("WithdrawPage.scoreTips")}
- </span>
- <span>
- <i className="mr-[.1rem] font-bold">R$</i>
- {wallet.score}
- </span>
- </li>
- <li className={"mb-[0.0694rem]"}>
- <span className="mr-[.1rem] inline-block w-[.6rem]">
- {t("WithdrawPage.pointTips")}
- </span>
- <span>
- <i className="mr-[.1rem] font-bold">R$</i>
- {wallet.point}
- </span>
- </li>
- <li>
- <div className={"flex items-center pt-[.1rem]"}>
- <ProgressBar
- percent={faltaData.percent} //faltaData.percent
- className={"mr-[0.0694rem] flex-1"}
- style={{
- "--fill-color": "#11de68",
- "--track-color": "#8f9498",
- "--track-width": "0.0694rem",
- }}
- />
- <span>{faltaData.percent}%</span>
- </div>
- </li>
- <div>
- <span className="mr-[.05rem]">FALTA APOSTAR</span>
- <span>
- <i className="mr-[.05rem] font-bold">R$</i>
- {faltaData.wait}
- </span>
- </div>
- <div className="mt-[.2rem] flex items-center justify-center">
- {!faltaData.canWithdraw && (
- <Button
- color={"primary"}
- className={"mx-auto flex-1 rounded-[.2rem_!important] font-bold"}
- style={{
- "--background-color": "#11de68",
- "--border-color": "#11de68",
- "--text-color": "#12171a",
- }}
- onClick={() => router.push("/")}
- >
- Comece o jogo
- </Button>
- )}
- {faltaData.canWithdraw && (
- <Button
- color={"primary"}
- className={"ml-[30px] flex-1 rounded-[.2rem_!important] font-bold"}
- style={{
- "--background-color": "#11de68",
- "--border-color": "#11de68",
- "--text-color": "#12171a",
- }}
- onClick={() => {
- scoreRef.current?.onClose();
- // extractHandler();
- }}
- >
- Bônus de retirada
- </Button>
- )}
- </div>
- </ul>
- </TipsModal>
- {/* 提现拦截 */}
- {/* <TipsModal
- title={
- <div className="text-left">
- <div className="text-[.12rem] text-[#fff]">
- Atualmente, existem jogos de bônus
- </div>
- <div className="text-[.12rem] text-[#ebc71f]">
- inacabados que não podem iniciar saques.
- </div>
- </div>
- }
- ref={gameModelRef}
- getContainer={document.querySelector("#app")}
- className={styles.gameModal}
- >
- <div className="pt-[.2rem]">
- <span>Bônus</span>
- <i className="mx-[.1rem]">R$</i>
- <span>{faltaData.point}</span>
- </div>
- <div className={"flex items-center"}>
- <ProgressBar
- percent={faltaData.percentPoint}
- className={"mr-[0.0694rem] flex-1"}
- style={{
- "--fill-color": "#11de68",
- "--track-color": "#8f9498",
- "--track-width": "0.0694rem",
- }}
- />
- <span>{faltaData.percentPoint}%</span>
- </div>
- <div className="pb-[.2rem]">FALTA APOSTAR R$ {faltaData.waitPoint}</div>
- <div className={"mt-[0.0694rem] flex justify-center"}>
- <Button
- color={"primary"}
- className={"ml-[30px] flex-1 rounded-[.2rem_!important]"}
- style={{
- "--background-color": "#11de68",
- "--border-color": "#11de68",
- "--text-color": "#12171a",
- }}
- onClick={goGame}
- >
- Para jogos
- </Button>
- </div>
- </TipsModal>
- <TipsModal
- title={
- <div className="text-left">
- <div className="text-[.16rem] text-[#11de68]">Saque bem-sucedida.</div>
- <div className="text-[.14rem] text-[#fff]">
- Seu bônus será liberado. Tem certeza?
- </div>
- </div>
- }
- visible={true}
- ref={successModelRef}
- getContainer={document.querySelector("#app")}
- className={styles.gameModal}
- >
- <div className="pt-[.2rem]">
- <span>Bônus</span>
- <i className="mx-[.1rem]">R$</i>
- <span>{faltaData.point}</span>
- </div>
- <div className={"flex items-center"}>
- <ProgressBar
- percent={faltaData.percentPoint}
- className={"mr-[0.0694rem] flex-1"}
- style={{
- "--fill-color": "#11de68",
- "--track-color": "#8f9498",
- "--track-width": "0.0694rem",
- }}
- />
- <span>{faltaData.percentPoint}%</span>
- </div>
- <div className="pb-[.2rem]">FALTA APOSTAR R$ {faltaData.waitPoint}</div>
- <div className={"mt-[0.0694rem] flex justify-center"}>
- <Button
- color={"primary"}
- className={"ml-[30px] flex-1 rounded-[.2rem_!important]"}
- style={{
- "--background-color": "#ebc71f",
- "--border-color": "#ebc71f",
- "--text-color": "#12171a",
- }}
- onClick={() => successModelRef.current?.onClose()}
- >
- Cancelar
- </Button>
- <Button
- color={"primary"}
- className={"ml-[30px] flex-1 rounded-[.2rem_!important]"}
- style={{
- "--background-color": "#11de68",
- "--border-color": "#11de68",
- "--text-color": "#12171a",
- }}
- >
- confirmação
- </Button>
- </div>
- </TipsModal> */}
- </div>
- );
- };
- export default Withdraw;
|